package com.zhuanzhuan.hero.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bj58.youpin.common.utils.json.JsonUtils;
import com.zhuanzhuan.hero.user.consts.NumConsts;
import com.zhuanzhuan.hero.user.converter.LabelConverter;
import com.zhuanzhuan.hero.user.dto.backend.RelateBusinessLabelDTO;
import com.zhuanzhuan.hero.user.entity.HeroLabelInfo;
import com.zhuanzhuan.hero.user.entity.HeroUserInfo;
import com.zhuanzhuan.hero.user.entity.HeroUserLabelRelation;
import com.zhuanzhuan.hero.user.enums.ExceptionMsgEnum;
import com.zhuanzhuan.hero.user.enums.LabelStateEnum;
import com.zhuanzhuan.hero.user.enums.LabelTypeEnum;
import com.zhuanzhuan.hero.user.enums.StateEnum;
import com.zhuanzhuan.hero.user.exception.BusinessException;
import com.zhuanzhuan.hero.user.mapper.HeroUserLabelRelationMapper;
import com.zhuanzhuan.hero.user.mq.dto.BackBusinessLabelUpdateMsg;
import com.zhuanzhuan.hero.user.mq.dto.BaseUserMsg;
import com.zhuanzhuan.hero.user.mq.producer.HeroUserProducer;
import com.zhuanzhuan.hero.user.pojo.bo.LabelInfoQueryBO;
import com.zhuanzhuan.hero.user.pojo.bo.QueryUserLabelRelateBO;
import com.zhuanzhuan.hero.user.pojo.po.LabelInfoPO;
import com.zhuanzhuan.hero.user.pojo.po.QueryBusinessLabelRelatePO;
import com.zhuanzhuan.hero.user.service.HeroLabelInfoService;
import com.zhuanzhuan.hero.user.service.HeroUserInfoService;
import com.zhuanzhuan.hero.user.service.HeroUserLabelRelationService;
import com.zhuanzhuan.hero.user.util.Assert;
import com.zhuanzhuan.hero.user.util.AsyncUtil;
import com.zhuanzhuan.hero.user.vo.label.BatchRelateBusinessLabelVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * dal Interface:HeroUserLabelRelation
 * @author hanjunjun
 * @date 2024-6-21
 */
@Service
@Slf4j
public class HeroUserLabelRelationServiceImpl extends ServiceImpl<HeroUserLabelRelationMapper, HeroUserLabelRelation>
    implements HeroUserLabelRelationService {

    @Autowired
    private HeroUserLabelRelationMapper userLabelRelationMapper;

    @Resource
    private HeroUserInfoService userInfoService;

    @Resource
    private HeroUserProducer heroUserProducer;

    @Resource
    private HeroLabelInfoService labelInfoService;

    @Override
    public List<HeroUserLabelRelation> queryUserRealateLabels(Long uid, Integer labelType) {
        HeroUserLabelRelation query = new HeroUserLabelRelation();
        query.setToUid(uid);
        query.setLabelType(labelType);
        query.setState(StateEnum.EFFECTIVE.getCode());
        return userLabelRelationMapper.select(query);
    }

    @Override
    public List<LabelInfoPO> queryUserRealateLabelInfos(List<Long> uids, Integer labelType) {
        return userLabelRelationMapper.queryUserRealateLabelInfos(uids, labelType);
    }

    @Override
    public void delByUidAndLabelType(List<Long> uids, Integer labelType, Long excludeLabelId) {
        log.info("delByUidAndLabelType uids={}", JsonUtils.toJsonWithoutNull(uids));
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.IS_DELETED.getCode())
            .in(HeroUserLabelRelation::getToUid, uids)
            .eq(HeroUserLabelRelation::getLabelType, labelType)
            .ne(Objects.nonNull(excludeLabelId), HeroUserLabelRelation::getLabelId, excludeLabelId);
        this.update(updateWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delByUidsAndLabelId(List<Long> uids, HeroLabelInfo labelInfo, Long operaterUid) {
        log.info("delByUidsAndLabelId uids={}, labelInfo={}, operaterUid={}", JsonUtils.toJsonWithoutNull(uids),
            JsonUtils.toJsonWithoutNull(labelInfo), operaterUid);
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        uids = uids.stream().distinct().collect(Collectors.toList());
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.IS_DELETED.getCode())
            .set(HeroUserLabelRelation::getUpdateBy, Objects.nonNull(operaterUid) ? operaterUid : NumConsts.SYSTEM_CODE)
            .eq(HeroUserLabelRelation::getLabelId, labelInfo.getId())
            .in(HeroUserLabelRelation::getToUid, uids);
        this.update(updateWrapper);

        //标签关联数自减
//        labelInfoService.increRelatedNum(labelInfo.getId(), -uids.size());

        //如果是经营标签，发送mq
        if (LabelTypeEnum.BUSINESS.getCode().equals(labelInfo.getLabelType())) {
            this.sendLabelRelationUpdateMsg(labelInfo, uids, BackBusinessLabelUpdateMsg.UNBOUND);
        }
    }

    @Override
    public void delByUidAndLabelIds(Long uid, List<Long> labelIds, Long operaterUid) {
        log.info("delByUidAndLabelIds uid={}, labelIds={}, operaterUid={}", uid,
            JsonUtils.toJsonWithoutNull(labelIds), operaterUid);
        if (Objects.isNull(uid) || CollectionUtils.isEmpty(labelIds)) {
            return;
        }
        labelIds = labelIds.stream().distinct().collect(Collectors.toList());
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.IS_DELETED.getCode())
            .set(HeroUserLabelRelation::getUpdateBy, Objects.nonNull(operaterUid) ? operaterUid : NumConsts.SYSTEM_CODE)
            .eq(HeroUserLabelRelation::getToUid, uid)
            .in(HeroUserLabelRelation::getLabelId, labelIds);
        this.update(updateWrapper);
    }

    @Override
    public void delByLabelIds(List<Long> labelIds, Long operaterUid) {
        log.info("delUserLabelRelateByLabelIds labelIds={}", JsonUtils.toJsonWithoutNull(labelIds));
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.IS_DELETED.getCode())
            .set(HeroUserLabelRelation::getUpdateBy, operaterUid)
            .in(HeroUserLabelRelation::getLabelId, labelIds);
        this.update(updateWrapper);
    }

    @Override
    public void effectiveByLabelIds(List<Long> labelIds, Long operaterUid) {
        log.info("effectiveByLabelIds labelIds={}", JsonUtils.toJsonWithoutNull(labelIds));
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.EFFECTIVE.getCode())
            .set(HeroUserLabelRelation::getUpdateBy, operaterUid)
            .in(HeroUserLabelRelation::getLabelId, labelIds)
            .eq(HeroUserLabelRelation::getState, StateEnum.INVALID.getCode());
        this.update(updateWrapper);
    }

    @Override
    public void invalidByLabelIds(List<Long> labelIds, Long operaterUid) {
        log.info("invalidByLabelIds labelIds={}", JsonUtils.toJsonWithoutNull(labelIds));
        LambdaUpdateWrapper<HeroUserLabelRelation> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(HeroUserLabelRelation::getState, StateEnum.INVALID.getCode())
            .set(HeroUserLabelRelation::getUpdateBy, operaterUid)
            .in(HeroUserLabelRelation::getLabelId, labelIds)
            .eq(HeroUserLabelRelation::getState, StateEnum.EFFECTIVE.getCode());
        this.update(updateWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BatchRelateBusinessLabelVO labelRelateUsers(HeroLabelInfo labelInfo, RelateBusinessLabelDTO relateBusinessLabelDTO) {
        log.info("labelRelateUsers param={}", JsonUtils.toJsonWithoutNull(relateBusinessLabelDTO));
        if (LabelTypeEnum.BUSINESS.getCode().equals(labelInfo.getLabelType())) {
            List<Long> toUids = relateBusinessLabelDTO.getToUids();
            if (CollectionUtils.isEmpty(toUids)) {
                log.info("toUids为空");
                return BatchRelateBusinessLabelVO.buildSuccess();
            }

            //筛选出不存在的用户
            List<HeroUserInfo> users = userInfoService.listByUid(toUids);
            List<Long> canRelateUids = users.stream().map(HeroUserInfo::getUid).distinct().collect(Collectors.toList());
            log.info("existUids={}", canRelateUids);
            //绑定失败的uid   需要返回给前端展示
            List<Long> noExistUids = toUids.stream().filter(uid -> !canRelateUids.contains(uid)).collect(Collectors.toList());
            log.info("noExistUids={}", noExistUids);
            if (CollectionUtils.isEmpty(canRelateUids)) {
                log.info("没有有效的用户");
                return BatchRelateBusinessLabelVO.buildSuccess(noExistUids);
            }

            //筛选出已经关联的用户  不能重复关联
            List<QueryBusinessLabelRelatePO> relatedUsers = this.queryLabelRelatedUsers(labelInfo.getId());
            if (CollectionUtils.isNotEmpty(relatedUsers)) {
                List<Long> relatedUids = relatedUsers.stream().map(QueryBusinessLabelRelatePO::getRelatedUid)
                    .collect(Collectors.toList());
                canRelateUids.removeIf(relatedUids::contains);
            }

            log.info("canRelateUids={}", canRelateUids);
            if (CollectionUtils.isEmpty(canRelateUids)) {
                log.info("这批用户都已经关联过了，不重复关联");
                return BatchRelateBusinessLabelVO.buildSuccess(noExistUids);
            }

            //每个用户只能关联一个运营标签，将已有的关联关系删除    新标签是启用状态才能删除旧的关联关系
            boolean newLabelEffective = LabelStateEnum.EFFECTIVE.getCode().equals(labelInfo.getLabelState());
            if (newLabelEffective) {
                //用户取消旧的关联关系
                this.delByUidAndLabelType(canRelateUids, LabelTypeEnum.BUSINESS.getCode(), null);
            }

            //保存关联关系  若标签是未启用，则关联关系置为未生效
            Long operaterUid = relateBusinessLabelDTO.getOperaterUid();
            Integer relationState = newLabelEffective ? StateEnum.EFFECTIVE.getCode() : StateEnum.INVALID.getCode();
            List<HeroUserLabelRelation> saveList = canRelateUids.stream().map(toUid -> this.buildEntity(operaterUid, toUid,
                LabelTypeEnum.BUSINESS.getCode(), labelInfo.getId(), relationState)).collect(Collectors.toList());
            this.saveBatch(saveList);

            //如果绑定关系生效 发送mq
            if (newLabelEffective) {
                this.sendLabelRelationUpdateMsg(labelInfo, relateBusinessLabelDTO.getToUids(),
                    BackBusinessLabelUpdateMsg.BOUND);
            }

            return BatchRelateBusinessLabelVO.buildSuccess(noExistUids);
        }

        throw new BusinessException(ExceptionMsgEnum.PARAM_ERROR);
    }

    @Override
    public void sendLabelRelationUpdateMsg(HeroLabelInfo labelInfo, List<Long> uids, Integer boundType) {
        if (CollectionUtils.isEmpty(uids)) {
            return;
        }
        AsyncUtil.run(() -> {
            uids.forEach(uid -> {
                BackBusinessLabelUpdateMsg msg = new BackBusinessLabelUpdateMsg(uid, labelInfo.getId(),
                    labelInfo.getLabelName(), labelInfo.getLabelIcon(), boundType);
                heroUserProducer.sendBackBusinessLabelUpdate(msg);
            });
        });
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void userRelateLabels(Long uid, Integer labelType, List<Long> labelIds) {
        log.info("用户关联多个标签 uid={}, labelType={}, labelIds={}", uid, labelType, JsonUtils.toJsonWithoutNull(labelIds));

        //更新用户-标签关联关系  该删的删该增的增
        boolean hasModify = this.updateUserLabelRelation(uid, labelIds, labelType);
        if (!hasModify) {
            log.info("标签没有变更");
        }

        //发送mq给搜广推  在上一层更新了个人简介，发送mq的地方二期优化
        if (LabelTypeEnum.MANAGEMENT.getCode().equals(labelType)) {
            log.info("修改经营标签发送mq");
            if (!heroUserProducer.sendBusinessLabelUpdate(new BaseUserMsg(uid))) {
                log.error("修改经营标签发送mq失败");
            }
        } else if (LabelTypeEnum.ADVANTAGE.getCode().equals(labelType)) {
            log.info("修改优势介绍发送mq");
            if (!heroUserProducer.sendAdvantagesLabelUpdate(new BaseUserMsg(uid))) {
                log.error("修改优势介绍发送mq失败");
            }
        }
    }

    @Override
    public List<QueryBusinessLabelRelatePO> queryLabelRelatedUsers(Long labelId) {
        Assert.notNull(labelId);
        QueryUserLabelRelateBO query = new QueryUserLabelRelateBO(labelId);
        query.setStates(Arrays.asList(StateEnum.EFFECTIVE.getCode(), StateEnum.INVALID.getCode()));
        return this.queryByParam(query);
    }

    @Override
    public List<QueryBusinessLabelRelatePO> queryByParam(QueryUserLabelRelateBO queryUserLabelRelateBO) {
        return userLabelRelationMapper.queryParam(queryUserLabelRelateBO);
    }

    @Override
    public void increCertifiedNum(Long uid, List<Long> labelIds) {
       log.info("increCertifiedNum uid={} labelIds={}", uid, JsonUtils.toJsonWithoutNull(labelIds));
       getBaseMapper().increCertifiedNum(uid, labelIds);

       //同行认证数变更 发mq
        if (!heroUserProducer.sendFraternityAuthNumUpdate(new BaseUserMsg(uid))) {
            log.error("同行认证数变更发mq失败 uid={}", uid);
        }
    }

    @Override
    public void decreCertifiedNum(Long uid, List<Long> labelIds) {
        log.info("decreCertifiedNum uid={} labelIds={}", uid, JsonUtils.toJsonWithoutNull(labelIds));
        getBaseMapper().decreCertifiedNum(uid, labelIds);

        //同行认证数变更 发mq
        if (!heroUserProducer.sendFraternityAuthNumUpdate(new BaseUserMsg(uid))) {
            log.error("同行认证数变更发mq失败 uid={}", uid);
        }
    }

    @Override
    public boolean managementLabelIsPerfection(Long uid, List<LabelInfoPO> relatedManagementLabelInfos) {
        if (Objects.isNull(uid) && CollectionUtils.isEmpty(relatedManagementLabelInfos)) {
            throw new BusinessException(ExceptionMsgEnum.PARAM_ERROR);
        }
        if (CollectionUtils.isEmpty(relatedManagementLabelInfos)) {
            relatedManagementLabelInfos = this.queryUserRealateLabelInfos(Collections.singletonList(uid),
                LabelTypeEnum.MANAGEMENT.getCode());
        }

        //主营品类标签>=1
        LabelInfoQueryBO queryBO = LabelInfoQueryBO.builder().labelType(LabelTypeEnum.MANAGEMENT.getCode()).build();
        List<HeroLabelInfo> managementLabelInfos = labelInfoService.listByParam(queryBO);
        List<LabelInfoPO> businessCateChilds = LabelConverter.findBusinessCateChilds(relatedManagementLabelInfos, managementLabelInfos);
        if (CollectionUtils.isEmpty(businessCateChilds)) {
            return false;
        }
        HeroUserInfo userInfo = userInfoService.getUserByUid(uid);
        Assert.notNull(userInfo, ExceptionMsgEnum.DATA_NOT_EXIST);
        if (StringUtils.isBlank(userInfo.getPersonalIntroduction())) {
            return false;
        }

        return true;
    }

    private HeroUserLabelRelation convertHeroUserLabelRelation(Long labelId, Long uid, Integer labelType) {
        if (labelId == null) {
            return null;
        }
        HeroUserLabelRelation entity = new HeroUserLabelRelation();
        entity.setFromUid(uid);
        entity.setToUid(uid);
        entity.setLabelType(labelType);
        entity.setLabelId(labelId);
        entity.setState(StateEnum.EFFECTIVE.getCode());
        entity.setCreateBy(uid);
        entity.setUpdateBy(uid);
        return entity;
    }

    private HeroUserLabelRelation buildEntity(Long operaterUid, Long toUid, Integer labelType, Long labelId, Integer state) {
        HeroUserLabelRelation relation = new HeroUserLabelRelation();
        relation.setFromUid(operaterUid);
        relation.setToUid(toUid);
        relation.setLabelType(labelType);
        relation.setLabelId(labelId);
        relation.setState(state);
        relation.setCreateBy(operaterUid);
        relation.setUpdateBy(operaterUid);
        return relation;
    }

    /**
     * 更新用户-标签关联关系
     *
     * @param toUid
     * @param labelIds
     * @param labelType
     * @return void
     * @author  hanjunjun
     * @date 2024/8/9
     **/
    private boolean updateUserLabelRelation(Long toUid, List<Long> labelIds, Integer labelType) {
        //是否有变更
        boolean hasModify = false;

        //查询现有的
        List<LabelInfoPO> existRelatedLabels =
            this.queryUserRealateLabelInfos(Collections.singletonList(toUid), labelType);
        List<Long> existRelatedLabelIds =
            existRelatedLabels.stream().map(LabelInfoPO::getLabelId).distinct().collect(Collectors.toList());
        //需要删除的
        List<Long> delRelateLabelIds = existRelatedLabelIds.stream().filter(labelId -> !labelIds.contains(labelId))
            .collect(Collectors.toList());
        log.info("updateFraternityAuthRelation delRelateLabelIds={}", JsonUtils.toJsonWithoutNull(delRelateLabelIds));
        
        //需要新增的
        List<Long> insertRelateLabelIds = labelIds.stream().filter(labelId -> !existRelatedLabelIds.contains(labelId))
            .collect(Collectors.toList());
        log.info("updateFraternityAuthRelation insertRelateLabelIds={}", JsonUtils.toJsonWithoutNull(insertRelateLabelIds));

        if (CollectionUtils.isNotEmpty(delRelateLabelIds)) {
            hasModify = true;
            this.delByUidAndLabelIds(toUid, delRelateLabelIds, toUid);
        }
        if (CollectionUtils.isNotEmpty(insertRelateLabelIds)) {
            hasModify = true;
            List<HeroUserLabelRelation> saveRecords = insertRelateLabelIds.stream()
                .map(labelId -> this.convertHeroUserLabelRelation(labelId, toUid, labelType))
                .collect(Collectors.toList());
            HeroUserLabelRelationService proxySrvice = (HeroUserLabelRelationService) AopContext.currentProxy();
            proxySrvice.saveBatch(saveRecords);
        }

        return hasModify;
    }
}